﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using MvcGMaps.Models;
using MvcGMaps.ViewModels;
using MvcGMaps.Utils;


namespace MvcGMaps.DAL
{
    public class MarkerRepository : GenericRepository<Marker>
    {

        public MarkerRepository(MarkersDBEntities context) : base(context)
        { 
        
        }

        public IQueryable<JsonMarker> GetJsonMarkers()
        {
            var query = context.Markers.AsNoTracking().Select(m => new JsonMarker()
                {
                    MarkerID = m.MarkerID,
                    Latitude = m.Latitude,
                    Longitude = m.Longitude
                });

            return query;
        }

        public IQueryable<Marker> Get(SearchModel searchModel)
        {
            var localModel = searchModel;
            var filter = expressionBuilder(localModel);

            return Get(filter, i => i.OrderBy(q => q.AddedDate));
        }

        private Expression<Func<Marker, bool>> expressionBuilder(SearchModel model)
        {

            Expression<Func<Marker, bool>> filterMType = null;
            if (model.MarkerType > 0)
            {
                filterMType = m => m.TypeID == model.MarkerType;
            }
            else
            {
                filterMType = m => m.TypeID > 0;
            }

            Expression<Func<Marker, bool>> filterSType = null;
            if (model.StatusType > 0)
            {
                filterSType = m => m.StatusID == model.StatusType;
            }
            else
            {
                filterSType = m => m.StatusID > 0;
            }

            Expression<Func<Marker, bool>> filterDate = null;
            DateTime emptyDate = new DateTime(1, 1, 1);
            if (model.StartDate == emptyDate && model.EndDate != emptyDate)
            {
                DateTime endDate = model.EndDate.AddDays(1);
                filterDate = m => m.AddedDate < endDate;
            }
            else if (model.StartDate != emptyDate && model.EndDate == emptyDate)
            {
                filterDate = m => m.AddedDate >= model.StartDate;
            }
            else if (model.StartDate != emptyDate && model.EndDate != emptyDate)
            {
                DateTime endDate = model.EndDate.AddDays(1);
                filterDate = m => m.AddedDate >= model.StartDate && m.AddedDate < endDate;
            }

            var paramExpr = Expression.Parameter(typeof(Marker));
            var exprBody = Expression.And(filterMType.Body, filterSType.Body);

            exprBody = (BinaryExpression)new ParameterReplacer(paramExpr).Visit(exprBody);

            // Ужасно! Надо бы разбираться и переписать...
            Expression<Func<Marker, bool>> finalExpr = null;
            if (filterDate != null)
            {
                var intermediateExpr = Expression.Lambda<Func<Marker, bool>>(exprBody, paramExpr);
                var exprBody2 = Expression.And(intermediateExpr.Body, filterDate.Body);
                exprBody2 = (BinaryExpression)new ParameterReplacer(paramExpr).Visit(exprBody2);
                finalExpr = Expression.Lambda<Func<Marker, bool>>(exprBody2, paramExpr);
            }
            else
            {
                finalExpr = Expression.Lambda<Func<Marker, bool>>(exprBody, paramExpr);
            }

            return finalExpr;
        }
    }
}